/*-------------------------------------------------------------------------
 *
 * relscan.h
 *	  POSTGRES 关系扫描描述符定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/relscan.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef RELSCAN_H
#define RELSCAN_H

#include "access/htup_details.h"
#include "access/itup.h"
#include "port/atomics.h"
#include "storage/buf.h"
#include "storage/spin.h"
#include "utils/relcache.h"


struct ParallelTableScanDescData;

/*
 * 表扫描的通用描述符。 这是表扫描的基类，
 * 需要嵌入到各个 AM 的扫描中。
 */
typedef struct TableScanDescData
{
	/* 扫描参数 */
	Relation	rs_rd;			/* 堆关系描述符 */
	struct SnapshotData *rs_snapshot;	/* 要查看的快照 */
	int			rs_nkeys;		/* 扫描键的数量 */
	struct ScanKeyData *rs_key; /* 扫描键描述符的数组 */

	/* ItemPointers 范围，用于 table_scan_getnextslot_tidrange() 的扫描。 */
	ItemPointerData rs_mintid;
	ItemPointerData rs_maxtid;

	/*
	 * 有关扫描类型和行为的信息，ScanOptions 枚举的成员
	 * 的位掩码（参见 tableam.h）。
	 */
	uint32		rs_flags;

	struct ParallelTableScanDescData *rs_parallel;	/* 并行扫描
													 * 信息 */
} TableScanDescData;
typedef struct TableScanDescData *TableScanDesc;

/*
 * 并行表扫描的共享状态。
 *
 * 参与并行表扫描的每个后端在后端私有内存中都有自己的
 * TableScanDesc，这些对象都包含指向此结构的指针。
 * 这里的信息必须足够充分，以便在工作者加入扫描时
 * 正确初始化每个新的 TableScanDesc，并且它
 * 必须作为那些工作者的扫描信息。
 */
typedef struct ParallelTableScanDescData
{
	Oid			phs_relid;		/* 要扫描的关系的 OID */
	bool		phs_syncscan;	/* 是否报告位置以用于 syncscan 逻辑？ */
	bool		phs_snapshot_any;	/* SnapshotAny，而不是 phs_snapshot_data？ */
	Size		phs_snapshot_off;	/* 快照的数据 */
} ParallelTableScanDescData;
typedef struct ParallelTableScanDescData *ParallelTableScanDesc;

/*
 * 并行表扫描的共享状态，用于块导向存储。
 */
typedef struct ParallelBlockTableScanDescData
{
	ParallelTableScanDescData base;

	BlockNumber phs_nblocks;	/* 扫描开始时关系中的块数 */
	slock_t		phs_mutex;		/* 设置 startblock 的互斥 */
	BlockNumber phs_startblock; /* 起始块编号 */
	pg_atomic_uint64 phs_nallocated;	/* 到目前为止分配给
										 * 工作者的块数。 */
}			ParallelBlockTableScanDescData;
typedef struct ParallelBlockTableScanDescData *ParallelBlockTableScanDesc;

/*
 * 针对并行表扫描的每个后端状态，适用于块导向存储。
 */
typedef struct ParallelBlockTableScanWorkerData
{
	uint64		phsw_nallocated;	/* 当前扫描中的块数 */
	uint32		phsw_chunk_remaining;	/* 此块中的剩余块数 */
	uint32		phsw_chunk_size;	/* 为扫描分配的每个 I/O 块的数量 */
} ParallelBlockTableScanWorkerData;
typedef struct ParallelBlockTableScanWorkerData *ParallelBlockTableScanWorker;

/*
 * 基于索引从表中提取的基类。这是此类扫描的基类，
 * 需要嵌入到各个AM的相应结构中。
 */
typedef struct IndexFetchTableData
{
	Relation	rel;
} IndexFetchTableData;

/*
 * 我们对基于amgettuple和基于amgetbitmap的索引扫描使用相同的 
 * IndexScanDescData 结构。一些字段仅在基于amgettuple的扫描中相关。
 */
typedef struct IndexScanDescData
{
	/* 扫描参数 */
	Relation	heapRelation;	/* 堆关系描述符，或 NULL */
	Relation	indexRelation;	/* 索引关系描述符 */
	struct SnapshotData *xs_snapshot;	/* 要查看的快照 */
	int			numberOfKeys;	/* 索引限定条件数量 */
	int			numberOfOrderBys;	/* 排序操作符数量 */
	struct ScanKeyData *keyData;	/* 索引限定符描述符数组 */
	struct ScanKeyData *orderByData;	/* 排序操作符描述符数组 */
	bool		xs_want_itup;	/* 调用者请求索引元组 */
	bool		xs_temp_snap;	/* 在扫描结束时注销快照？ */

	/* 向索引 AM 发出关于杀死索引元组的信号 */
	bool		kill_prior_tuple;	/* 最后返回的元组已死亡 */
	bool		ignore_killed_tuples;	/* 不返回被杀死的条目 */
	bool		xactStartedInRecovery;	/* 防止杀死/看到已被杀死的元组 */

	/* 索引访问方法的私有状态 */
	void	   *opaque;			/* 访问方法特定信息 */

	/*
	 * 在仅索引扫描中，成功的 amgettuple 调用必须填充 
	 * xs_itup（和 xs_itupdesc）或 xs_hitup（和 xs_hitupdesc），以提供
	 * 扫描返回的数据。它可以同时填充这两个，在这种情况下将使用堆格式。
	 */
	IndexTuple	xs_itup;		/* AM 返回的索引元组 */
	struct TupleDescData *xs_itupdesc;	/* xs_itup 的行类型描述符 */
	HeapTuple	xs_hitup;		/* AM 返回的索引数据，作为 HeapTuple */
	struct TupleDescData *xs_hitupdesc; /* xs_hitup 的行类型描述符 */

	ItemPointerData xs_heaptid; /* 结果 */
	bool		xs_heap_continue;	/* T 表示必须继续查找，可能有
									 * 进一步的结果 */
	IndexFetchTableData *xs_heapfetch;

	bool		xs_recheck;		/* T 表示扫描键必须重新检查 */

	/*
	 * 当使用排序操作符进行提取时，根据索引，最后返回的元组的 
	 * ORDER BY 表达式的值。如果 xs_recheckorderby 为真，则这些
	 * 需要像扫描键一样重新检查，这里返回的值是实际值的下限。
	 */
	Datum	   *xs_orderbyvals;
	bool	   *xs_orderbynulls;
	bool		xs_recheckorderby;

	/* 并行索引扫描信息，位于共享内存中 */
	struct ParallelIndexScanDescData *parallel_scan;
}			IndexScanDescData;

/* 并行扫描的通用结构 */
typedef struct ParallelIndexScanDescData
{
	Oid			ps_relid;
	Oid			ps_indexid;
	Size		ps_offset;		/* am 特定结构的字节偏移量 */
	char		ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER];
}			ParallelIndexScanDescData;

struct TupleTableSlot;

/* 用于系统表的存储或索引扫描的结构 */
typedef struct SysScanDescData
{
	Relation	heap_rel;		/* 正在扫描的目录 */
	Relation	irel;			/* 如果进行堆扫描，则为 NULL */
	struct TableScanDescData *scan; /* 仅在存储扫描情况下有效 */
	struct IndexScanDescData *iscan;	/* 仅在索引扫描情况下有效 */
	struct SnapshotData *snapshot;	/* 快照在扫描结束时注销 */
	struct TupleTableSlot *slot;
}			SysScanDescData;

#endif							/* RELSCAN_H */
